#ifndef QLSAVDECODE_H
#define QLSAVDECODE_H

#define VIDEO_PICTURE_QUEUE_SIZE     1
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio

#define MAX_AUDIO_SIZE (25 * 16 * 1024)
#define MAX_VIDEO_SIZE (18 * 256 * 1024)

#include <QObject>
#include <QThread>
#include <QString>
#include <QImage>
#include <QMutex>
#include <QSemaphore>
#include <QPaintEvent>
#include <QtConcurrent>
#include <QFuture>

#include "qls_av_player_global.h"
#include "qls_av_packet_queue.h"

class QLsAVPlayer;
class QLsAVParam;

/* 根据解码后的视频数据 计算出视频的pts */
double SynchronizeVideo(QLsAVParam *avParam, AVFrame *srcFrame, double pts);
/**
 * @brief RaiseVolume	音量调节
 * @param buf			需要调节音量的音频数据块首地址指针
 * @param size			长度
 * @param uRepeat		重复次数，通常设为1
 * @param vol			增益倍数,可以小于1
 */
void RaiseVolume(char *buf, int size, int uRepeat, double vol);
/* 视频解码线程 */
int VDecodeThread(void *arg);
/* 音频回调函数 */
void ACallback(void *userdata, Uint8 *stream, int len);
/* 音频解码函数 */
int ADecode(QLsAVParam *avParam);

/* 音视频处理参数封装 */
class QLS_AV_PLAYER_EXPORT QLsAVParam
{
public:
    QLsAVParam(QLsAVPlayer *avPlayer = nullptr);
    ~QLsAVParam();

    /* 参数重置 */
    void ResetParam();

public:
    /* 音视频整体 */
    AVFormatContext *m_inputCtx;
    QLsAVPlayer *m_avPlayer;
    bool m_bDecodeThreadFinished; /* 解码线程完毕 */
    bool m_bDecodeFinished;       /* 解码完毕 */
    bool m_bQuit;                 /* 整体退出 */
    bool m_bPause;                /* 暂停 */
    bool m_bMute;                 /* 静音 */
    int m_bSeek;                  /* 跳转标志 */
    int64_t m_seekPos;            /* 跳转的位置(微秒) */
    double m_seekTime;   /* 跳转的时间(秒)(值为：m_seekPos / 1e6) */
    quint64 m_startTime; /* 开始播放视频的时间 */
    quint64 m_pauseStartTime; /* 暂停开始的时间 */
    bool m_bFirstPause; /* 第一次显示是否暂停(为了加载完视频有个预览界面) */

    /* 视频 */
    int m_vStreamIndex;            /* 视频里位置 */
    AVCodecContext *m_vCodecCtx;   /* 视频流信息 */
    AVCodec *m_vCodec;             /* 视频流解码器 */
    AVStream *m_vStream;           /* 视频流 */
    QLsAVPacketQueue *m_vPktQueue; /* 视频数据包缓冲区队列 */
    QFuture<void> m_vDecodeThread; /* 视频解码线程 */
    bool m_bVDecodeThreadFinished; /* 视频解码线程是否完成 */
    double m_vClock;               /* 视频时钟 */
    bool m_bVSeek;                 /* 视频跳转标志 */

    /* 音频 */
    int m_aStreamIndex;            /* 音频流位置 */
    AVCodecContext *m_aCodecCtx;   /* 音频流信息 */
    AVCodec *m_aCodec;             /* 音频流解码器 */
    AVStream *m_aStream;           /* 音频流 */
    QLsAVPacketQueue *m_aPktQueue; /* 音频数据包缓冲队列 */
    AVPacket m_aPacket;            /* 音频数据包 */
    bool m_bADecodeThreadFinished; /* 音频解码线程是否完成 */
    AVFrame *m_aFrame;             /* 解码出的音频数据 */
    float m_volume;                /* 音量增益系数 */
    double m_aClock;               /* 音频时钟 */
    bool m_bASeek;                 /* 音频跳转标志 */
    AVFrame *m_aFrameReSample;     /* 重采样后的解码音频数据 */
    SwrContext *m_aSwrCtx;         /* 用于解码后的音频格式转换 */

    /* 音频解码 */
    unsigned int audio_buf_size;
    unsigned int audio_buf_index;
    uint8_t *audio_pkt_data;
    int audio_pkt_size;
    uint8_t *audio_buf;
    DECLARE_ALIGNED(16, uint8_t, audio_buf2)[AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
    AVSampleFormat audio_src_fmt;
    AVSampleFormat audio_tgt_fmt;
    int audio_src_channels;
    int audio_tgt_channels;
    int64_t audio_src_channel_layout;
    int64_t audio_tgt_channel_layout;
    int audio_src_freq;
    int audio_tgt_freq;
    int audio_hw_buf_size;

    /* 重采样 */
    AVSampleFormat in_sample_fmt;  //输入的采样格式
    AVSampleFormat out_sample_fmt; //输出的采样格式 16bit PCM
    int in_sample_rate;            //输入的采样率
    int out_sample_rate;           //输出的采样率
    int in_ch_layout;
    int out_ch_layout;
};

/* 音视频解码 */
class QLS_AV_PLAYER_EXPORT QLsAVPlayer : public QObject
{
    Q_OBJECT
public:
    /* 播放状态 */
    enum QLsPlayerStatus
    {
        Player_Default = 0, /* 默认 */
        Player_Playing,     /* 播放中 */
        Player_Pause,       /* 暂停 */
        Player_Stop         /* 停止 */
    };

public:
    QLsAVPlayer(QObject *parent = nullptr);
    ~QLsAVPlayer();

    /* ---------- 多线程信号槽 ---------- */
    /* 加载 */
    void Load();
    /* 显示一帧图像 */
    void DisplayVideo(QImage img);
    /* 重新播放 */
    bool Replay();
    /* 播放 */
    bool Play();
    /* 暂停 */
    bool Pause();
    /* 停止 */
    bool Stop(bool bWait = false);
    /* 跳转(微秒) */
    void Seek(qint64 pos);
    /* 静音 */
    bool mute() const;
    void setMute(const bool &bMute);
    /* 音量 */
    void SetVolume(const float &volume);

    /* 路径 */
    QString AVUrl() const;
    void setAVUrl(const QString &AVUrl);

    /* 音视频播放状态 */
    QLsPlayerStatus playerStatus() const;

    /* 播放进度/当前时间 */
    qint64 curTime() const;

    /* 总时长 */
    qint64 totalTime() const;

    /* 设置是否显示预览(第一次加载视频是否暂停) */
    void setPreview(const bool &bFirstPause);

signals:
    /* 获取一帧图像 的信号 */
    void sigGetOneFrame(QImage);
    /* 状态变化 的信号 */
    void sigStatusChange(QLsPlayerStatus);
    /* 视频时长变化 的信号 */
    void sigTotalTimeChange(qint64);

private:
    /* 解码开始 */
    void DecodeStart();
    /* 解码结束 */
    void DecodeEnd();
    /**
     * SDL打开音频设备
     * 打开SDL，并设置播放的格式为：AUDIO_S16LSB、双声道、44100Hz
     * 后期使用 ffmpeg
     * 解码完音频后，需要重采样成和这个一样的格式，否则播放会有杂音
     */
    bool SDLOpenADevice();
    /* SDL关闭音频设备 */
    void SDLCloseADevice();
    /* 打开要解码的音视频流 */
    bool AVOpenInput(const QString &url);
    /* 获取音视频流的位置信息 */
    void AVGetStreamIndex();
    /* 获取音频流信息 */
    bool AVGetAStreamParam();
    /* 获取视频流信息 */
    bool AVGetVStreamParam();
    /* 解码跳转 */
    void AVDecodeSeek();
    /* 解码 */
    void Decoding();

private slots:
    /* ---------- 多线程信号槽 ---------- */
    /* 加载 的槽函数 */
    void slotLoad();

signals:
    /* ---------- 多线程信号槽 ---------- */
    /* 加载 的信号 */
    void sigLoad();

private:
    QThread *m_thread;
    QString m_AVUrl;                /* 路径 */
    QLsAVParam *m_avParam;          /* 音视频处理参数封装 */
    QLsPlayerStatus m_playerStatus; /* 音视频播放状态 */
    SDL_AudioDeviceID m_aDeviceID;  /* 音频设备id */
};

#endif // QLSAVDECODE_H
